Java1.5中的concurrent包下提供了很多的工具类,本次来讲述这些实用的类。
CountDownLatch
它主要用来管理一组相关的线程,使得某个线程,要等待其他所有线程执行完后在执行。常用的有两个方法:countdown()
和await()
.它的用法很简单,可分为以下三步:
new CountDownLatch(10)
,设置需要等待的线程数量,这是设置为10。CountDownLatch.await()
, 调用该方法的线程立刻阻塞,等待需要等待的线程数量为0后重新变成可运行态。CountDownLath.countdown()
,使得该CountDownLatch需要等待的线程数量减1。
代码示例:
|
|
实现原理
它是自定义的AQS组件,之前对AQS同步框架已有详细介绍,这里就不在虚岁。有了AQS框架的实现子类sync
的实例,CountDownLatch
就变得异常简单,它就是一个简单的共享锁的应用。下面是它三个主要方法的源码:
由上可知,CountDownLatch
整个过程就是设置共享锁的数量,然后不断释放锁的过程。
CyclicBarrier
这个类的作用是允许一组线程相互等待,直到到达某个公共的屏障点,常用的情景是一组线程,它们不时的互相等待,而且,它是可以重用的,就像它的名字一样,它叫栅栏,要等到所有线程都执行完了,在一起继续做其他事。
那么,一定觉得CountDownLatch
和CyclicBarrier
很像吧。它们之间的区别有:
后者可以重复使用,而前者不行
后者是N个线程相互等待,然后一起继续执行;而前者在于一个线程等待N个线程,N个线程执行完后可以继续执行,而等待的线程需要在N个线程执行完
countDown
后再执行。
代码示例
下面来看看它的具体使用:
以上,四个线程分别随机睡眠一段时间,等到睡醒后再等到其他所有线程都醒来后再一起执行。
原理分析
CyclicBarrier
的实现不是直接基于AQS的,而是借助了ReentrantLock
,源码在这里就不贴,调用await
方法,会转而执行dowait()
,在函数里,使用了lock,Condition,和一个count计数变量,主要实现的功能如下:
使用lock,保证多线程对CyclicBarrier的内部数据操作都是互斥的
当该线程是最后一个到达的,唤醒其他所有线程,并继续执行下去
当该线程不是最后一个线程到达时,进入Condition自旋等待。
Semaphore
在操作系统中,也有Semaphore的概念,它表示资源的可用数量,获取资源,信号量减1,释放资源,信号量加1;当信号量为0时,无法获取资源。Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目.
Java中的Semaphore类则是完全实现了一样的功能,允许最多n个线程获取该信号量。
代码示例
|
|
原理分析
它也是基于AQS框架实现同步的,AQS的同步状态state
就是信号量的数量,以下是Semaphore
中的关键方法获取共享锁的实现代码: